package org.jflame.context.filemanager;

import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;

/**
 * 文件管理接口,实现文件的上传,下载
 * 
 * @author charles.zhang
 */
public interface IFileManager extends Closeable {

    /**
     * 保存/上传文件
     * 
     * @param file 要保存的文件File
     * @param saveDir 保存目录,相对于文件服务根目录,可为null.
     * @param fileMeta 文件元数据或附带属性,只适用于可保存无数据的文件服务,可为null.
     * @return 返回在文件系统中的唯一标识key,可能是文件路径或文件名
     * @throws FileAccessException
     */
    String save(File file, String saveDir, Map<String,String> fileMeta) throws FileAccessException;

    /**
     * 保存/上传文件,从输入流中读取文件
     * 
     * @param fileStream 文件输入流
     * @param filePath 文件保存相对路径, 包括文件名
     * @param fileMeta 文件元数据或附带属性,只适用于可保存元数据的文件服务,可为null.
     * @param replaceExisting 是否覆盖同名文件,true表示保留文件名如果已有同名文件将会覆盖,false生成一个新的唯一文件名
     * @return 返回在文件系统中的唯一标识key,可能是文件路径或文件名
     * @throws FileAccessException
     */
    String save(InputStream fileStream, String filePath, Map<String,String> fileMeta, boolean replaceExisting)
            throws FileAccessException;

    /**
     * 保存/上传文件,从输入流中读取文件
     * 
     * @param fileStream 文件输入流
     * @param filePath 文件保存相对路径, 包括文件名
     * @param fileMeta 文件元数据或附带属性,只适用于可保存元数据的文件服务,可为null.
     * @return 返回在文件系统中的唯一标识key,可能是文件路径或文件名
     * @throws FileAccessException
     */
    default public String save(InputStream fileStream, String filePath, Map<String,String> fileMeta)
            throws FileAccessException {
        return save(fileStream, filePath, fileMeta, false);
    }

    /**
     * 保存/上传文件,从输入流中读取文件
     * 
     * @param fileBytes 文件数据byte数组
     * @param filePath 文件保存相对路径, 包括文件名
     * @param fileMeta 文件元数据或附带属性,只适用于可保存元数据的文件服务,可为null.
     * @return 返回在文件系统中的唯一标识key,可能是文件路径或文件名
     * @throws FileAccessException
     */
    default public String save(byte[] fileBytes, String filePath, Map<String,String> fileMeta)
            throws FileAccessException {
        return save(new ByteArrayInputStream(fileBytes), filePath, fileMeta);
    }

    /**
     * 读取/下载文件,返回文件流. <strong>注:请主动关闭流</strong>
     * 
     * @param filePath 文件的唯一标识key,可能是文件路径或文件名
     * @return InputStream
     * @throws FileAccessException
     */
    InputStream readStream(String filePath) throws FileAccessException;

    /**
     * 读取/下载文件,返回文件的字节数组byte[]
     * 
     * @param filePath 文件的唯一标识key,可能是文件路径或文件名
     * @return 文件byte[]
     * @throws FileAccessException 文件不存在或读取出错
     */
    byte[] readBytes(String filePath) throws FileAccessException;

    /**
     * 读取/下载文件,返回File对象,文件保存到临时目录
     * 
     * @param filePath 文件的唯一标识key,可能是文件路径或文件名
     * @return File对象
     * @throws FileAccessException 文件不存在或读取出错
     */
    File read(String filePath) throws FileAccessException;

    /**
     * 下载文件
     * 
     * @param filePath 文件的唯一标识key,可能是文件路径或文件名
     * @param savePath 文件本地路径
     * @throws FileAccessException
     */
    void download(String filePath, Path savePath) throws FileAccessException;

    /**
     * 删除文件
     * 
     * @param fileKey 文件的唯一标识key,可能是文件路径或文件名
     * @return 返回成功删除的数量
     */
    int delete(String... fileKey) throws FileAccessException;

    /**
     * 指定父级目录，删除下面的文件
     * 
     * @param parent 父级目录或分组
     * @param fileKeys 文件的唯一标识key,可能是文件路径或文件名
     * @return 返回成功删除的数量
     */
    int delete(String parent, String[] fileKeys) throws FileAccessException;

    /**
     * 文件复制
     * 
     * @param srcFilePath 源文件路径
     * @param destFilePath 目标文件路径,如果传空表示同目录复制, 如果以文件系统的路径分隔符(\或/)结尾表示复制到目录,此时文件名不变.
     * @return 新的文件路径
     */
    String copy(String srcFilePath, String destFilePath) throws FileAccessException;

    /**
     * 列出目录下所有文件名,不包含子文件夹的文件
     * 
     * @param dir 目录名
     * @param maxFiles 列举的最大文件个数,0表示列出所有
     * @param isExcludeDir 是否不包含目录,true=不包含
     * @return 目录不存在返回null,空目录返回空的list
     * @throws FileAccessException
     */
    List<String> listFiles(String dir, int maxFiles, boolean isExcludeDir) throws FileAccessException;

    /**
     * 文件key转为外部访问地址
     * 
     * @param filePath 相对路径
     * @return
     */
    String toRequestUrl(String filePath);

}
